package org.example.registry;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;

public class RpcRegistry {
    public static final int SO_BACKLOG_VALUE = 1024;
    private static final int PORT = 8080;


    private void start() {
        // ServerSocket / ServerSocketChannel

        // 基于NIO来实现
        // Selector 主线程，Work线程
        // parentGroup  select的线程 主线程池
        // childGroup   具体的worker线程池，执行具体的逻辑的
        // EventLoopGroup 默认的线程池数量是 核心数的2倍

        // 初始化主线程吃 selector
        EventLoopGroup boosGroup = new NioEventLoopGroup();
        // 子线程池初始化，具体对应客户端的处理逻辑
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        ServerBootstrap server = new ServerBootstrap()
                .group(boosGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        // 在Netty 中，把所有的业务逻辑处理全部归宗到一个队列中
                        // 这个队列中包含了各种各样的处理罗及，对这些处理逻辑在Netty中有一个封装
                        // 封装成了一个对象，无所化串行任务队列 Pipline
                        ChannelPipeline pipeline = socketChannel.pipeline();

                        // 就是对我们处理逻辑的封装
                        // 对自定义协议的内容要进行编、解码
                        pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
                        pipeline.addLast(new LengthFieldPrepender(4));
                        // 实参处理
                        pipeline.addLast("decoder", new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null)));
                        pipeline.addLast("encoder", new ObjectEncoder());

                        // 前面的编解码，就是完成对数据的解析
                        // 最后一步，执行属于自己的逻辑
                        // 1、注册，给每一个对象起一个名字，   也就是对外提供服务的名字
                        // 2、服务位置要做一个登记
                        pipeline.addLast(new RpcRegistryHandler());

                    }
                })
                // 设置最大的SelectionKey的数量
                .option(ChannelOption.SO_BACKLOG, SO_BACKLOG_VALUE)
                // 保证子线程可以回收利用
                .childOption(ChannelOption.SO_KEEPALIVE, true);

        try {
            // 正式启动服务，相当于用一个死循环开始轮询
            ChannelFuture future = server.bind(PORT).sync();
            System.out.println("netty RPC Registry start listen at " + PORT);
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            boosGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }


    public static void main(String[] args) {
        new RpcRegistry().start();
    }
}
